Proyecto Minería de Datos: Predicción de posiciones finales de una partida de PUBG

Integrantes: Cristóbal Miranda - Pablo Miranda - Ignacio Vallejos

Introducción

PlayerUnknown’s Battlegrounds (PUBG) es un videojuego de batalla en línea masivo, el juego es del género Battle Royale que combina los elementos de un videojuego de supervivencia con la jugabilidad de un último jugador en pie. En él hasta 100 jugadores saltan en paracaídas desde un avión a una isla, donde tienen que buscar armas y equipo para matar a otros jugadores y así ser el último hombre en pie, dentro del mapa hay una área segura que disminuye a medida que avanza el tiempo, dirigiendo a los jugadores sobrevivientes a áreas más reducidas y forzando así enfrentamientos.

En este trabajo se utilizara un dataset obtenido de kaggle.com, que es de una competencia abierta. Link a la competencia

Descripción del problema

Motivación

En una partida de PUBG participan hasta 100 jugadores. Los jugadores pueden estar en equipos, los cuales son clasificados al final de la partida basados en cuantros equipos están vivos cuando éstos son eliminados. En cada partida los jugadores pueden recoger distintas armas, municiones y equipo, además pueden revivir compañeros derribados siempre y cuando éstos no mueran, pueden conducir vehículos, nadar, correr, disparar y experimentar todas las consecuencias de ésto, como por ejemplo ser atropellados y ser eliminados.

Cuál será la mejor estrategia para ganar en PUBG?. Evitar peleas y esperar hasta que queden pocos jugadores para pelear, o ir buscando peleas a diestra y siniestra durante toda la partida?

Temática o problemática central y describir cómo se abordará inicialmente

Predecir la posición en el marcador en la que quedará un jugador al final de la partida, según sus acciones en un juego de PUBG para partidas en solitario, en duos y en grupos, tanto para las variantes de 3era persona como de 1era persona.

Inicialmente se van a probar varios modelos predictivos utilizando el dataset de entrenamiento y se comparan según su precisión medida con el dataset de prueba. Utilizaremos gran mayoría de los métodos de clasificación vistos en clases.

Hipótesis

  • En una partida a partir de los datos con los que terminan sus participantes, se puede predecir qué jugadores quedan en el 10% más alto.
  • El jugador que se mueve más tiene más probabilidades de ganar.
  • El jugador que más jugadores mata tiene más probabilidades de ganar.
  • El jugador que más daño hace tiene más probabilidades de ganar.

Análisis Exploratorio

Descripción de los datos que se van a utilizar

Se utilizarán datos de más de 65.000 partidas distribuídos en 2 datasets, uno para entrenar y otro para testear.

Se importan librerías a utilizar

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns 
import warnings

warnings.filterwarnings('ignore')

Se leen los datos

In [2]:
train_data = pd.read_csv("train_V2.csv")
train_data.head()
Out[2]:
Id groupId matchId assists boosts damageDealt DBNOs headshotKills heals killPlace ... revives rideDistance roadKills swimDistance teamKills vehicleDestroys walkDistance weaponsAcquired winPoints winPlacePerc
0 7f96b2f878858a 4d4b580de459be a10357fd1a4a91 0 0 0.00 0 0 0 60 ... 0 0.0000 0 0.00 0 0 244.80 1 1466 0.4444
1 eef90569b9d03c 684d5656442f9e aeb375fc57110c 0 0 91.47 0 0 0 57 ... 0 0.0045 0 11.04 0 0 1434.00 5 0 0.6400
2 1eaf90ac73de72 6a4a42c3245a74 110163d8bb94ae 1 0 68.00 0 0 0 47 ... 0 0.0000 0 0.00 0 0 161.80 2 0 0.7755
3 4616d365dd2853 a930a9c79cd721 f1f1f4ef412d7e 0 0 32.90 0 0 0 75 ... 0 0.0000 0 0.00 0 0 202.70 3 0 0.1667
4 315c96c26c9aac de04010b3458dd 6dc8ff871e21e6 0 0 100.00 0 0 0 45 ... 0 0.0000 0 0.00 0 0 49.75 2 0 0.1875

5 rows × 29 columns

Una descripción de las columnas

In [3]:
train_data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4446966 entries, 0 to 4446965
Data columns (total 29 columns):
Id                 object
groupId            object
matchId            object
assists            int64
boosts             int64
damageDealt        float64
DBNOs              int64
headshotKills      int64
heals              int64
killPlace          int64
killPoints         int64
kills              int64
killStreaks        int64
longestKill        float64
matchDuration      int64
matchType          object
maxPlace           int64
numGroups          int64
rankPoints         int64
revives            int64
rideDistance       float64
roadKills          int64
swimDistance       float64
teamKills          int64
vehicleDestroys    int64
walkDistance       float64
weaponsAcquired    int64
winPoints          int64
winPlacePerc       float64
dtypes: float64(6), int64(19), object(4)
memory usage: 983.9+ MB

Para nuestro análisis no nos interesan las partidas no ranqueadas, por lo que seran eliminadas.

Se eliminan partidas no ranqueadas

In [4]:
initial_elements = train_data.shape[0]
relevant_matches = ['solo', 'solo-fpp', 'duo', 'duo-fpp', 'squad', 'squad-fpp']
non_custom = train_data[train_data.matchType.isin(relevant_matches)]

train_data = non_custom
non_custom = None
removed_elements = initial_elements - train_data.shape[0]

print("Se han quitado %d elementos cuyos modos de juego no nos sirven del dataset" % removed_elements)
Se han quitado 35267 elementos cuyos modos de juego no nos sirven del dataset

Lo siguiente es un histograma sobre la cantidad de jugadores de cada equipo en todo el dataset de entrenamiento. Esto es para saber si la gente prefiere jugar sola o en equipo y notar que los grupos de 5 o más personas son de partidas personalizadas, no corresponden al modo normal de juego.

Se obtiene histograma de distribución de jugadores por equipos

In [5]:
ggid = train_data.groupby(['groupId'])[['Id']].count()

ggid.loc[ggid['Id'] >= 8] = '8+'
plt.figure(figsize=(20,10))
sns.countplot(ggid['Id'].astype('str').sort_values())

plt.xlabel('Jugadores por grupo', fontsize=20)
plt.ylabel('Cantidad de grupos', fontsize=20)
plt.suptitle('Distribución de jugadores por equipos', fontsize=35)
plt.tick_params(labelsize=20)

plt.show()

Interpretación: Las partidas con más de 4 jugadores ocurren porque al crearse el grupo pueden entrar o salir jugadores y todos quedan registrados en el grupo, pero estos jugadores quedan sin datos en la partida (no matan a nadie, no recorren nada, etc), por lo que generan ruido. Dicho ésto eliminaremos todos los grupos que figuren con más de 4 jugadores, ésto no nos quita el ruido para las partidas de un jugador o 2 jugadores, pero para esos tipos de partidas se eliminaran los grupos correspondientes al momento de ocuparlos.

Se eliminan grupos que tengan más de 4 jugadores

In [6]:
ggid = train_data.groupby(['groupId'])[['Id']].count()
lesser_5_ggid = ggid.drop(ggid[ggid['Id'] >= 5].index)
ggid = None
selected_l5 = train_data.loc[train_data['groupId'].isin(lesser_5_ggid.index)]
removed_elements = train_data.shape[0] - selected_l5.shape[0]
lesser_5_ggid = None

train_data = selected_l5
print("Se han quitado %d elementos con 5 o más integrates por grupo del dataset" % removed_elements)
Se han quitado 726082 elementos con 5 o más integrates por grupo del dataset

Lo siguiente es revisar la cantidad de grupos por juego. Esto para saber si la gente prefiere jugar sola o en grupo.

Se obtiene cantidad de grupos por juego

In [7]:
mmggid = train_data.groupby(['matchId'])[['groupId']].count()
mmggid = mmggid['groupId']

mmggid.loc[mmggid <= 10] = 10
mmggid.loc[(mmggid <= 20) & (mmggid > 10)] = 20
mmggid.loc[(mmggid <= 30) & (mmggid > 20)] = 30
mmggid.loc[(mmggid <= 40) & (mmggid > 30)] = 40
mmggid.loc[(mmggid <= 50) & (mmggid > 40)] = 50
mmggid.loc[(mmggid <= 60) & (mmggid > 50)] = 60
mmggid.loc[(mmggid <= 70) & (mmggid > 60)] = 70
mmggid.loc[(mmggid <= 80) & (mmggid > 70)] = 80
mmggid.loc[(mmggid <= 90) & (mmggid > 80)] = 90
mmggid.loc[(mmggid <= 100) & (mmggid > 90)] = 100


mmggid.loc[mmggid == 10] = '1-10'
mmggid.loc[mmggid == 20] = '11-20'
mmggid.loc[mmggid == 30] = '21-30'
mmggid.loc[mmggid == 40] = '31-40'
mmggid.loc[mmggid == 50] = '41-50'
mmggid.loc[mmggid == 60] = '51-60'
mmggid.loc[mmggid == 70] = '61-70'
mmggid.loc[mmggid == 80] = '71-80'
mmggid.loc[mmggid == 90] = '81-90'
mmggid.loc[mmggid == 100] = '91-100'


plt.figure(figsize=(20,10))
sns.countplot(mmggid.astype('str').sort_values())

plt.xlabel('equipos por juego ', fontsize=20)
plt.ylabel('Cantidad de partidas', fontsize=20)
plt.suptitle('Distribución de equipos por partida', fontsize=35)
plt.tick_params(labelsize=20)

plt.show()
mmggid = None

Interpretación: Se ve que la mayoría de los grupos se encuentran en el rango 91-100 que corresponde mayoritariamente a los equipos en partidas de un solo jugador

Lo siguiente que se verá es la distribución de eliminaciones de todo el dataset.

Se obtiene el promedio de eliminaciones

In [10]:
prom_kills = round(train_data['kills'].mean(), 4)
print(f'El jugador promedio mata {prom_kills} personas.')
El jugador promedio mata 1.001 personas.

Otra medición es el promedio de kills por partida.

In [12]:
prom_kills_game = round(train_data.groupby(['matchId'])[['kills']].mean()['kills'].mean(), 4)
print(f'El jugador promedio mata a {prom_kills_game} personas por partida.')
El jugador promedio mata a 1.0103 personas por partida.

Por último en cuanto a la distribución de eliminaciones, se tiene la distribución de eliminaciones de todo el dataset dada por el siguiente histograma.

In [13]:
kills_data = train_data.copy()
kills_data.loc[kills_data['kills'] >= 6] = '6+'
plt.figure(figsize=(20,10))
sns.countplot(kills_data['kills'].astype('str').sort_values())

plt.xlabel('Eliminaciones', fontsize=20)
plt.ylabel('Cantidad de jugadores', fontsize=20)
plt.suptitle('Distribución de eliminaciones de los jugadores', fontsize=35)
plt.tick_params(labelsize=15)

plt.show()
kills_data = None

Interpretación: De esto se ve que la mayoría de los jugadores no logran tener eliminaciones y que una parte muy reducida de los jugadores logra tener 6 o más eliminaciones.

Ahora se verá cómo afectan las eliminaciones en ganar el juego.

Cuánta gente gana sin tener eliminaciones?

In [15]:
win_nokill = len(train_data[(train_data['kills'] == 0) & (train_data['winPlacePerc'] == 1.0)])
print("Hay %d jugadores en todo el dataset que ganaron una partida y no hicieron ninguna kill." % win_nokill)
res = (win_nokill/len(train_data))*100
print("Hay %.4f%% de jugadores en todo el dataset que ganaron una partida y no hicieron ninguna kill." % res)
Hay 16231 jugadores en todo el dataset que ganaron una partida y no hicieron ninguna kill.
Hay 0.4404% de jugadores en todo el dataset que ganaron una partida y no hicieron ninguna kill.

Cuánta gente gana sin hacer daño?

In [16]:
win_nodamage = len(train_data[(train_data['damageDealt'] == 0) & (train_data['winPlacePerc'] == 1.0)])
print("Hay %d jugadores en todo el dataset que ganaron una partida y no hicieron daño." % win_nodamage)
res = (win_nodamage/len(train_data))*100
print("Hay %.4f%% de jugadores en todo el dataset que ganaron una partida y no hicieron daño." % res)
Hay 4636 jugadores en todo el dataset que ganaron una partida y no hicieron daño.
Hay 0.1258% de jugadores en todo el dataset que ganaron una partida y no hicieron daño.

Distribución de headshots (disparos a la cabeza)

In [18]:
headshot_data = train_data.copy()
headshot_data.loc[headshot_data['headshotKills'] >= 5] = '5+'
plt.figure(figsize=(20,10))
sns.countplot(headshot_data['headshotKills'].astype('str').sort_values())

plt.xlabel('Tiros a la cabeza', fontsize=20)
plt.ylabel('Cantidad de jugadores', fontsize=20)
plt.suptitle('Distribución de tiros a la cabeza de los jugadores', fontsize=35)
plt.tick_params(labelsize=15)

plt.show()
headshot_data = None

Interpretación: De esto se ve que hay una gran cantidad de jugadores que no logran hacer eliminaciones por headshot y que significa que lograr hacerlos dan cuenta de una gran habilidad.

Otra característica importante que demuestra habilidad es la capacidad de ejecutar eliminaciones a distancia.

Se obtiene la distribución de distancias en las que se logró una eliminación

In [19]:
plt.figure(figsize=(20,10))
sns.distplot(train_data['longestKill'])

plt.xlabel('Distancia de eliminación', fontsize=20)
plt.ylabel('Distribución de jugadores', fontsize=20)
plt.suptitle('Distribución de distancias de eliminación', fontsize=35)
plt.tick_params(labelsize=15)

plt.show()

Para interpretar este gráfico se calculan los siguientes resultados

Se obtienen distancia de eliminación máxima, mínima y promedio

In [20]:
min_lk = train_data['longestKill'].min()
max_lk = train_data['longestKill'].max()
mean_lk = train_data['longestKill'].mean()
print("Minima distancia de eliminación = %.3f" % min_lk)
print("Máxima distancia de eliminación = %.3f" % max_lk)
print("Promedio de distancia de eliminación = %.3f" % mean_lk)
Minima distancia de eliminación = 0.000
Máxima distancia de eliminación = 1003.000
Promedio de distancia de eliminación = 25.591

Interpretación: El promedio de los jugadores logra una distancia de aproximadamente 25 metros y la mínima distancia es 0 porque quienes no sacan kills se les cuenta como 0 distancia de eliminación. El máximo de 1052 metros se debe a cómo se toma este dato, que es la distancia entre el jugador que muere y el que lo incapacita, pero un jugador puede incapacitar a otro y escapar en un auto, lo cual hace que esta distancia aumente mucho, también puede darse el caso de un jugador de gran habilidad que atropella a otro y escapa.

Esto hace que este dato no sea relevante para partidas con mas de un jugador por equipo. Para partidas de un jugador por equipo, este dato si es relevante, porque el jugador al ser noqueado queda eliminado automaticamente.

¿Cuántos jugadores quedan con distancia de eliminación igual a 0?

In [22]:
dist_elim0 = len(train_data[train_data['longestKill'] == 0])
print("La cantidad de jugadores que quedaron con distancia de eliminación igual a 0 son: %d" % dist_elim0)
La cantidad de jugadores que quedaron con distancia de eliminación igual a 0 son: 2004032

Con respecto a la totalidad del dataset esto corresponde a

In [33]:
print("%.1f%%" % (float(dist_elim0)/(train_data.shape[0] + 1)*100))
54.4%

Se obtiene la distribución de la destrucción de vehículos

In [34]:
plt.figure(figsize=(20,10))

sns.countplot(train_data['vehicleDestroys'].astype('str').sort_values())

plt.xlabel('Vehículos destruidos', fontsize=20)
plt.ylabel('Cantidad de jugadores', fontsize=20)
plt.suptitle('Distribución de vehículos destruidos de los jugadores', fontsize=35)
plt.tick_params(labelsize=15)

plt.show()

Se obtiene el porcentaje de jugadores que destruyen vehículos

In [36]:
veh_destr = len(train_data[train_data['vehicleDestroys'] > 0])
no_ve_destr = len(train_data[train_data['vehicleDestroys'] == 0])
print ("El %.2f%% de los jugadores destruyen vehículos." % (veh_destr*100.0 /len(train_data)))
print ("El %.2f%% de los jugadores no destruyen vehículos." % (no_ve_destr*100.0 /len(train_data)))
El 0.82% de los jugadores destruyen vehículos.
El 99.18% de los jugadores no destruyen vehículos.

Interpretación: Los jugadores que destruyen vehículos son muy pocos, por lo que es un potencial indicador de habilidad.

Se obtiene la distribución de distancia recorrida a pie por los jugadores (walkDistance)

In [37]:
plt.figure(figsize=(20,10))
sns.distplot(train_data['walkDistance'])
plt.xlabel('Distancia recorrida [m]', fontsize=20)
plt.ylabel('Cantidad de jugadores', fontsize=20)
plt.suptitle('Distribución de distancia recorrida a pie por los jugadores', fontsize=35)
plt.tick_params(labelsize=15)
plt.show()

Se obtienen máximo, mínimo y promedio

In [38]:
no_wd = len(train_data[train_data['walkDistance'] == 0])
min_wd = train_data['walkDistance'].min()
max_wd = train_data['walkDistance'].max()
mean_wd = train_data['walkDistance'].mean()
print("Minima distancia recorrida a pie = %.3f" % min_wd)
print("Máxima distancia recorrida a pie = %.3f" % max_wd)
print("Promedio de distancia recorrida a pie = %.3f" % mean_wd)
print("\nPorcentaje de jugadores que recorre 0 metros a pie: %.3f%%" % (no_wd* 100.0 / len(train_data)))
Minima distancia recorrida a pie = 0.000
Máxima distancia recorrida a pie = 25780.000
Promedio de distancia recorrida a pie = 1275.552

Porcentaje de jugadores que recorre 0 metros a pie: 1.261%

Interpretación: El promedio de los jugadores recorre a pie una distancia aproximada de 1275 metros y un 1.2% de los jugadores recorre 0 metros, estos son jugadores que mueren antes de moverse, ya sea por desconexiones o jugadores que no hacen nada (afk: away from keyboard), y gente que cae en el agua y muere antes de salir, también la máxima distancia recorrida es de 25.780 metros lo cual probablemente sea por uso de software tramposo, ya que el tiempo que dura una partida no alcanza para recorrer 17 kms a pie

Se obtiene la distribución de distancia nadada por jugadores

In [39]:
plt.figure(figsize=(20,10))
sns.distplot(train_data['swimDistance'])
plt.xlabel('Distancia nadada [m]', fontsize=20)
plt.ylabel('Cantidad de jugadores', fontsize=20)
plt.suptitle('Distribución de distancia nadada por los jugadores', fontsize=35)
plt.tick_params(labelsize=15)
plt.show()

Se estudian valores extremos y el promedio

In [40]:
no_sw = len(train_data[train_data['swimDistance'] == 0])
min_sw = train_data['swimDistance'].min()
max_sw = train_data['swimDistance'].max()
mean_sw = train_data['swimDistance'].mean()
print("Minima distancia nadada = %.3f" % min_sw)
print("Máxima distancia nadada = %.3f" % max_sw)
print("Promedio de distancia nadada = %.3f" % mean_sw)
print("\nPorcentaje de jugadores que nada 0 metros: %.3f%%" % (no_sw* 100.0 / len(train_data)))
Minima distancia nadada = 0.000
Máxima distancia nadada = 3514.000
Promedio de distancia nadada = 5.110

Porcentaje de jugadores que nada 0 metros: 92.738%

Interpretación: El promedio de los jugadores nada una distancia aproximada de 5 metros, el record es de 3.5km. El 92.7% de los jugadores no nada, esto se debe mayoritariamente a que en el agua no se puede disparar y que se va considerablemente más lento que en tierra. Usando conocimiento del juego, se podría considerar no tan relevante este atributo en cuanto a la habilidad del jugador, porque pueden haber jugadores muy buenos que nunca entran al agua o jugadores muy malos que tampoco lo hacen.

Se obtiene la distribución de items de curación utilizados (heals)

In [41]:
heal_items = train_data.copy()
heal_items = heal_items['heals'].sort_values()
heal_items.loc[heal_items >= 20] = '20+'

plt.figure(figsize=(20,10))

sns.countplot(heal_items)

plt.xlabel('Items de curación utilizados', fontsize=20)
plt.ylabel('Cantidad de jugadores', fontsize=20)
plt.suptitle('Distribución de cantidad de items de curación utilizados por jugadores', fontsize=35)
plt.tick_params(labelsize=15)

plt.show()
heal_items = None

Valores extremos y promedio

In [43]:
no_hl = len(train_data[train_data['heals'] == 0])
min_hl = train_data['heals'].min()
max_hl = train_data['heals'].max()
mean_hl = train_data['heals'].mean()
print("Minima cantidad de items de curación utilizada = %.3f" % min_hl)
print("Máxima cantidad de items de curación utilizada = %.3f" % max_hl)
print("Promedio de items de curación utilizados = %.3f" % mean_hl)
print("\nPorcentaje de jugadores que no utilizan items de curación: %.3f%%" % (no_hl* 100.0 / len(train_data)))
Minima cantidad de items de curación utilizada = 0.000
Máxima cantidad de items de curación utilizada = 80.000
Promedio de items de curación utilizados = 1.512

Porcentaje de jugadores que no utilizan items de curación: 56.014%

Interpretación: El promedio de los jugadores utiliza 1 item de curación por partida y el máximo es 80. También se puede apreciar que poco mas de la mitad de los jugadores no utiliza items de curación, ésto se debe a que muchos mueren después de su primer enfrentamiento, son jugadores que no logran ni una kill en las partidas.

Matriz de correlación

Se hace para conocer que tan correlacionados son los atributos entre, par a par.

Primero se define una función que servira para obtener las correlaciones entre atributos

In [47]:
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

def corr_graph(input_data, extra_title='', to_drop_cols=['matchType', 'Id', 'groupId', 'matchId', 'DBNOs', 'revives']):
  plt.figure(figsize=(15,15))
  
  solos_cp = input_data.copy()
  solos_cp = solos_cp.drop(to_drop_cols, axis=1)
  scorr=solos_cp.corr()

  tofind = np.where(scorr > 0.7)
  indexes = []
  cols_ = []
  cols_2 = solos_cp.columns.values
  for i in range(len(tofind[0])):
    if tofind[0][i] < tofind[1][i]:
      pair = (tofind[0][i], tofind[1][i])
      indexes.append(pair)

      cols_.append((cols_2[pair[0]], cols_2[pair[1]]))

  ax = plt.gca()
  cax = ax.matshow(scorr,cmap=plt.cm.YlOrRd)
  ax.set_xticklabels(cols_2, rotation='vertical', fontsize=20)
  ax.set_yticklabels(cols_2, fontsize=20)
  ax.set_xticks(np.arange(0, len(cols_2), 1))
  ax.set_yticks(np.arange(0, len(cols_2), 1))
  ax.tick_params(axis='x', labelbottom=True, labeltop=False)

  cbar = ax.figure.colorbar(cax, ax=ax, shrink = 0.8)
  cbar.ax.set_ylabel("Correlation", rotation=-90, va="bottom", fontsize= 25)
  cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(which='both'), fontsize=15)

  plt.grid()
  plt.title('Matriz de correlación de atributos %s' % extra_title, fontsize=35)
  
  plt.show()

  print("Los pares con mayor correlación son:\n")
  for col in cols_:
    print('\t -', col[0], "con", col[1])
    
  print('\n')
  
  best_correlations = scorr['winPlacePerc'].sort_values(ascending=False)[1:6]
  
  print("Las 5 variables que tiene mayor correlación con winPlacePerc son:\n")
  for index in range(len(best_correlations)):
    print('\t -', best_correlations[best_correlations == best_correlations[index]].index[0], "-", best_correlations[index])
  print("\n")
In [48]:
corr_graph(train_data, extra_title='para el dataset completo')
Los pares con mayor correlación son:

	 - damageDealt con kills
	 - damageDealt con killStreaks
	 - killPoints con winPoints
	 - kills con killStreaks
	 - maxPlace con numGroups
	 - walkDistance con winPlacePerc


Las 5 variables que tiene mayor correlación con winPlacePerc son:

	 - walkDistance - 0.807486978767317
	 - boosts - 0.6285897736537016
	 - weaponsAcquired - 0.5973117501996711
	 - damageDealt - 0.4429065036296923
	 - kills - 0.4243943825407083


En lo siguiente se filtraran los datos del dataset completo segun el matchType.

Filtros segun matchType

In [49]:
solos = train_data[train_data.matchType == 'solo']
duos = train_data[train_data.matchType == 'duo']
squad = train_data[train_data.matchType == 'squad'] 
solosfpp = train_data[train_data.matchType == 'solo-fpp']
duosfpp = train_data[train_data.matchType == 'duo-fpp']
squadfpp = train_data[train_data.matchType == 'squad-fpp']

Se estudia la matriz de correlación para cada filtro

In [50]:
corr_graph(solos, 'para matchType=solos')
Los pares con mayor correlación son:

	 - damageDealt con kills
	 - killPoints con winPoints
	 - kills con killStreaks
	 - maxPlace con numGroups
	 - walkDistance con winPlacePerc


Las 5 variables que tiene mayor correlación con winPlacePerc son:

	 - walkDistance - 0.7928833159360524
	 - weaponsAcquired - 0.6408330700547005
	 - boosts - 0.6286242364677547
	 - damageDealt - 0.5043546142680163
	 - kills - 0.491413769250542


In [53]:
corr_graph(solosfpp, 'para matchType=solosfpp')
Los pares con mayor correlación son:

	 - damageDealt con kills
	 - killPoints con winPoints
	 - kills con killStreaks
	 - maxPlace con numGroups
	 - walkDistance con winPlacePerc


Las 5 variables que tiene mayor correlación con winPlacePerc son:

	 - walkDistance - 0.8202810001146931
	 - weaponsAcquired - 0.6824787164234726
	 - boosts - 0.6435463346451432
	 - damageDealt - 0.5115058041569217
	 - kills - 0.5012582269880637


Comparación solos con solosfpp: Se ve que a grandes rasgos no hay diferencia

In [51]:
corr_graph(duos, 'para matchType=duos')
Los pares con mayor correlación son:

	 - damageDealt con kills
	 - damageDealt con killStreaks
	 - killPoints con winPoints
	 - kills con killStreaks
	 - maxPlace con numGroups
	 - walkDistance con winPlacePerc


Las 5 variables que tiene mayor correlación con winPlacePerc son:

	 - walkDistance - 0.8200061492630139
	 - boosts - 0.6444230835448966
	 - weaponsAcquired - 0.6103558982248689
	 - damageDealt - 0.462395892246414
	 - kills - 0.4421791137225243


In [52]:
corr_graph(squad, 'para matchType=squad')
Los pares con mayor correlación son:

	 - damageDealt con kills
	 - damageDealt con killStreaks
	 - killPoints con winPoints
	 - kills con killStreaks
	 - maxPlace con numGroups
	 - walkDistance con winPlacePerc


Las 5 variables que tiene mayor correlación con winPlacePerc son:

	 - walkDistance - 0.7635909526636555
	 - boosts - 0.587667846256741
	 - weaponsAcquired - 0.48592619873435017
	 - damageDealt - 0.37769081461490367
	 - heals - 0.373362278782806


Interpretación: A grandes rasgos no hay diferencias muy notorias de las matrices de correlación entre los distintos matchTypes. De igual forma no hay diferencia notoria entre los modos de primera y tercera persona.

Clasificación

En primer lugar se importan cosas necesarias que ya se hicieron en las secciones anteriores

In [1]:
from common import *

Para esta parte se necesitan definir ciertas funciones que ayudaran a generar resultados rápidamente. Para ahorrar espacio en este informe se definen en el archivo classification_utils.py.

In [2]:
from classification_utils import *

Especificaciones de la clasificación

Se quiere predecir si un jugador tiene buen rendimiento en la partida según el lugar en el que quedó. Como el dato que se quiere predecir esta como un número real entre 0 y 1, lo que se hace es particionar en dos categorías según el criterio winPlacePerc >= 0.9, donde la clase positiva significa estar en el mejor 10% de una partida.

Para que haya un balance de clases se utilizara la función select_train_data_cls que hace subsampling equilibrado en las dos clases. Para estos experimentos se seleccionarán 15 mil elementos por clase.

En lo siguiente se hace clasificación para partidas solo, utilizando todos los atributos. Ciertamente se ignoran algunos que son atributos de ID no relevantes para la clasificación.

Se hace clasificación para partidas solo

In [3]:
all_columns_relevant = get_columns_relevant(solos)
X, y =  select_train_data_cls(solos, all_columns_relevant, percentage=0.9, to_select=15000)
solo_results_kills = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills, ' en partidas Solo, con todos los atributos ')
Class winners: 15000, Class losers: 15000

Se quitan atributos redundantes segun el análisis de correlación

In [4]:
all_columns_relevant = get_columns_relevant(solos)
all_columns_relevant.remove('killStreaks')
all_columns_relevant.remove('damageDealt')
all_columns_relevant.remove('winPoints')
all_columns_relevant.remove('numGroups')

X, y =  select_train_data_cls(solos, all_columns_relevant, percentage=0.9, to_select=15000)

solo_results_kills = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills, ' en partidas Solo, quitando atributos redundantes ')
Class winners: 15000, Class losers: 15000

Se utilizan los atributos que están mas correlacionados con winPlacePerc

In [5]:
X, y =  select_train_data_cls(solos, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.9, to_select=15000)

solo_results_kills = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills, ' en partidas Solo, usando 5 atributos importantes')
Class winners: 15000, Class losers: 15000

Se prueba solo utilizando el atributo kills

In [6]:
X, y =  select_train_data_cls(solos, ['kills'], percentage=0.9, to_select=15000)
solo_results_kills = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills, ' en partidas Solo, usando kills')
Class winners: 15000, Class losers: 15000

Interpretación: Al utilizar un solo atributo, se ve el evidente impacto negativo que hay en el recall de los resultados.

Se prueba utilizando kills y walkDistance

In [7]:
X, y =  select_train_data_cls(solos, ['kills', 'walkDistance'], percentage=0.9, to_select=15000)
solo_results_kills_wd = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills_wd, ' en partidas Solo, usando kills y walkDistance')
Class winners: 15000, Class losers: 15000

Interpretación: De lo visto hasta ahora se ve que utilizando los 5 atributos más correlacionados con winPlacePerc se obtienen resultados muy similares a usando todos los atributos y a usar todos los atributos excepto redundantes. Por lo tanto desde ahora en adelante se hara la clasificación utilizando los 5 atributos más importantes.

Se prueban los 5 atributos más importantes con el modo Solo en primera persona

In [8]:
X, y =  select_train_data_cls(solosfpp, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.9, to_select=15000)
solo_results_kills = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills, ' en partidas Solo, usando 5 atributos importantes')
Class winners: 15000, Class losers: 15000

Comparación con modo solo: Se ve que comparado con el modo solo no tiene diferencias significativas en los resuiltados. Por lo tanto ya no tiene demasiado sentido seguir comparando entre los modos primera y tercera persona. De ahora en adelante solo se utilizará para el análisis los modos en tercera persona (sin el sufijo fpp).

Clasificación utilizando los 5 atributos más correlacionados a winPlacePerc en el modo Duos

In [9]:
X, y =  select_train_data_cls(duos, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.9, to_select=15000)
solo_results_kills = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills, ' en partidas Duo, usando 5 atributos importantes')
Class winners: 15000, Class losers: 15000

Clasificación utilizando los 5 atributos más correlacionados a winPlacePerc en el modo Squad

In [10]:
X, y =  select_train_data_cls(squad, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.9, to_select=15000)
solo_results_kills = run_the_classifiers(X, y)
plot_bar_chart(solo_results_kills, ' en partidas Squad, usando 5 atributos importantes')
Class winners: 15000, Class losers: 15000

Interpretación: Nuevamente se ve que no hay tanta diferencia en los resultados al variar segun el matchType.

Variando el número de clases de predicción

También resulta interesante ver el caso en que se particiona el espacio de winPlacePerc en más de dos clases y ver como afecta al poder predictivo de los clasificadores. El espacio se particiona segun percentiles, en vez de una partición desbalanceada como la que se tenía antes de >= 0.9.

Para este análisis solo se utilizarán partidas con matchType = solos, porque no hay tanta diferencia de resultados al cambiar el matchType.

Se usan todas las columnas no redundantes con 10 categorías

In [11]:
all_columns_relevant = get_columns_relevant(solos)
all_columns_relevant.remove('killStreaks')
all_columns_relevant.remove('damageDealt')
all_columns_relevant.remove('winPoints')
all_columns_relevant.remove('numGroups')

X, y =  select_train_data_cls_several_categories(solos, all_columns_relevant, categories=10, to_select=15000)

solo_results = run_the_classifiers(X, y, average='micro')
plot_bar_chart(solo_results, ' en partidas Solo, con 10 categorias')
Class winners: 30000, Class losers: 15000
Out train data y is:
[9 0 0 ... 1 9 7]
Unicas
[9 0 5 3 4 1 2 7 8 6]

Se usan todas las columnas no redundantes con 6 categorías

In [12]:
X, y =  select_train_data_cls_several_categories(solos, all_columns_relevant, categories=6, to_select=15000)

solo_results = run_the_classifiers(X, y, average='micro')
plot_bar_chart(solo_results, ' en partidas Solo, con 6 categorias')
Class winners: 30000, Class losers: 15000
Out train data y is:
[4 3 4 ... 5 0 0]
Unicas
[4 3 1 5 0 2]

Se usan todas las columnas no redundantes con 3 categorías

In [13]:
X, y =  select_train_data_cls_several_categories(solos, all_columns_relevant, categories=3, to_select=15000)

solo_results_kills = run_the_classifiers(X, y, average='micro')
plot_bar_chart(solo_results_kills, ' en partidas Solo, con 3 categorias')
Class winners: 30000, Class losers: 15000
Out train data y is:
[0 1 1 ... 0 0 1]
Unicas
[0 1 2]

Interpretación: Se ve que mientras menos categorías, mayor el poder predictivo de los clasificadores.

Regresión

Como el atributo winPlacePerc es un valor real entre 0 y 1 que se quiere predecir, es necesario tener un modelo regresivo para este fin.

En este trabajo se prueban los regresores de Random Forest y Support Vector Machine.

Se importa código python que contiene funciones útiles para probar los modelos.

In [1]:
from common import *
from regression_utils import *

Para saber que hiper-parámetros utilizar en los regresores se utiliza GridSearchCV que busca de forma exhaustiva los mejores parámetros según una métrica que se especifica.

Grid search para Random Forest Regression

In [2]:
X, y = select_train_data_reg(solos, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.5, to_select=1000)
gs_random_fr(X, y)
Class winners: 1000, Class losers: 1000
# Tuning hyper-parameters for explained_variance

Best parameters set found on development set:
{'criterion': 'mae', 'max_depth': 5, 'min_samples_split': 16, 'n_estimators': 100}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.830
Mean Absolute Error: 	 0.082
Mean Squared Error: 	 0.017
Mean Squared Log Error: 	 0.008
Median Absolute Error: 	 0.054
R^2 Score, Variance Weighted: 	 0.828
R^2 Score, Uniform Average: 	 0.828
R^2 Score, Raw Values: 	 0.828
# Tuning hyper-parameters for neg_mean_absolute_error

Best parameters set found on development set:
{'criterion': 'mae', 'max_depth': 5, 'min_samples_split': 16, 'n_estimators': 300}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.830
Mean Absolute Error: 	 0.082
Mean Squared Error: 	 0.017
Mean Squared Log Error: 	 0.008
Median Absolute Error: 	 0.053
R^2 Score, Variance Weighted: 	 0.827
R^2 Score, Uniform Average: 	 0.827
R^2 Score, Raw Values: 	 0.827
# Tuning hyper-parameters for neg_mean_squared_error

Best parameters set found on development set:
{'criterion': 'mae', 'max_depth': 5, 'min_samples_split': 16, 'n_estimators': 200}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.830
Mean Absolute Error: 	 0.082
Mean Squared Error: 	 0.017
Mean Squared Log Error: 	 0.008
Median Absolute Error: 	 0.055
R^2 Score, Variance Weighted: 	 0.828
R^2 Score, Uniform Average: 	 0.828
R^2 Score, Raw Values: 	 0.828
# Tuning hyper-parameters for neg_mean_squared_log_error

Best parameters set found on development set:
{'criterion': 'mae', 'max_depth': 5, 'min_samples_split': 16, 'n_estimators': 100}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.830
Mean Absolute Error: 	 0.082
Mean Squared Error: 	 0.017
Mean Squared Log Error: 	 0.008
Median Absolute Error: 	 0.054
R^2 Score, Variance Weighted: 	 0.828
R^2 Score, Uniform Average: 	 0.828
R^2 Score, Raw Values: 	 0.828
# Tuning hyper-parameters for neg_median_absolute_error

Best parameters set found on development set:
{'criterion': 'mae', 'max_depth': 5, 'min_samples_split': 16, 'n_estimators': 200}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.830
Mean Absolute Error: 	 0.082
Mean Squared Error: 	 0.017
Mean Squared Log Error: 	 0.008
Median Absolute Error: 	 0.053
R^2 Score, Variance Weighted: 	 0.828
R^2 Score, Uniform Average: 	 0.828
R^2 Score, Raw Values: 	 0.828
# Tuning hyper-parameters for r2

Best parameters set found on development set:
{'criterion': 'mae', 'max_depth': 5, 'min_samples_split': 16, 'n_estimators': 300}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.829
Mean Absolute Error: 	 0.083
Mean Squared Error: 	 0.017
Mean Squared Log Error: 	 0.008
Median Absolute Error: 	 0.053
R^2 Score, Variance Weighted: 	 0.827
R^2 Score, Uniform Average: 	 0.827
R^2 Score, Raw Values: 	 0.827

De esto se ve que para distintos criterios se obtienen configuraciones parecidas, en pos de la eficiencia se usara la siguiente configuración, que es la que da mejor puntaje R^2:

'criterion': 'mse', 'max_depth': 4, 'min_samples_split': 2, 'n_estimators': 100

Grid search para SVR

In [3]:
X, y = select_train_data_reg(solos, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.5, to_select=1000)
gs_svr(X, y, n_jobs=3)
Class winners: 1000, Class losers: 1000
# Tuning hyper-parameters for explained_variance

Best parameters set found on development set:
{'C': 0.5, 'cache_size': 7000, 'epsilon': 0.001, 'kernel': 'rbf'}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.357
Mean Absolute Error: 	 0.210
Mean Squared Error: 	 0.065
Mean Squared Log Error: 	 0.029
Median Absolute Error: 	 0.200
R^2 Score, Variance Weighted: 	 0.353
R^2 Score, Uniform Average: 	 0.353
R^2 Score, Raw Values: 	 0.353
# Tuning hyper-parameters for neg_mean_absolute_error

Best parameters set found on development set:
{'C': 0.8, 'cache_size': 7000, 'epsilon': 0.001, 'kernel': 'rbf'}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.357
Mean Absolute Error: 	 0.210
Mean Squared Error: 	 0.065
Mean Squared Log Error: 	 0.029
Median Absolute Error: 	 0.199
R^2 Score, Variance Weighted: 	 0.352
R^2 Score, Uniform Average: 	 0.352
R^2 Score, Raw Values: 	 0.352
# Tuning hyper-parameters for neg_mean_squared_error

Best parameters set found on development set:
{'C': 0.5, 'cache_size': 7000, 'epsilon': 0.001, 'kernel': 'rbf'}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.357
Mean Absolute Error: 	 0.210
Mean Squared Error: 	 0.065
Mean Squared Log Error: 	 0.029
Median Absolute Error: 	 0.200
R^2 Score, Variance Weighted: 	 0.353
R^2 Score, Uniform Average: 	 0.353
R^2 Score, Raw Values: 	 0.353
# Tuning hyper-parameters for neg_mean_squared_log_error

Best parameters set found on development set:
{'C': 0.8, 'cache_size': 7000, 'epsilon': 0.001, 'kernel': 'rbf'}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.357
Mean Absolute Error: 	 0.210
Mean Squared Error: 	 0.065
Mean Squared Log Error: 	 0.029
Median Absolute Error: 	 0.199
R^2 Score, Variance Weighted: 	 0.352
R^2 Score, Uniform Average: 	 0.352
R^2 Score, Raw Values: 	 0.352
# Tuning hyper-parameters for neg_median_absolute_error

Best parameters set found on development set:
{'C': 1.5, 'cache_size': 7000, 'epsilon': 0.01, 'kernel': 'rbf'}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.351
Mean Absolute Error: 	 0.211
Mean Squared Error: 	 0.066
Mean Squared Log Error: 	 0.029
Median Absolute Error: 	 0.202
R^2 Score, Variance Weighted: 	 0.346
R^2 Score, Uniform Average: 	 0.346
R^2 Score, Raw Values: 	 0.346
# Tuning hyper-parameters for r2

Best parameters set found on development set:
{'C': 0.5, 'cache_size': 7000, 'epsilon': 0.001, 'kernel': 'rbf'}
Detailed Regression report:

The model is trained on the full development set.
The scores are computed on the full evaluation set.

Metrics
Explained Variance Score: 	 0.357
Mean Absolute Error: 	 0.210
Mean Squared Error: 	 0.065
Mean Squared Log Error: 	 0.029
Median Absolute Error: 	 0.200
R^2 Score, Variance Weighted: 	 0.353
R^2 Score, Uniform Average: 	 0.353
R^2 Score, Raw Values: 	 0.353

En este caso se ve que los parámetros que más se repiten son C=0.5 y epsilon=0.001, por lo que se usaran aquellos.

Se define la siguiente funcion utilitaria

In [4]:
def output_reg(rf_s, svm_s):
  print("Random Forest Regression Score = %.3f" % rf_s)
  print("Support Vector Machine Regression Score = %.3f" % svm_s)

Regresión para los 5 atributos más correlacionados a winPlacePerc, con matchType = solos

In [5]:
X, y =  select_train_data_reg(solos, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.5, to_select=15000)
rfs = random_forest_regressor_score(X, y)
svmrs = svm_regressor_score(X, y)
output_reg(rfs, svmrs)
Class winners: 15000, Class losers: 15000
Random Forest Regression Score = 0.804
Support Vector Machine Regression Score = 0.537

Regresión para los 5 atributos más correlacionados a winPlacePerc, con matchType = duos

In [6]:
X, y =  select_train_data_reg(duos, ['walkDistance', 'weaponsAcquired', 'boosts', 'damageDealt', 'kills'], percentage=0.5, to_select=15000)
rfs = random_forest_regressor_score(X, y)
svmrs = svm_regressor_score(X, y)
output_reg(rfs, svmrs)
Class winners: 15000, Class losers: 15000
Random Forest Regression Score = 0.803
Support Vector Machine Regression Score = 0.453

Regresión para los 5 atributos más correlacionados a winPlacePerc, con matchType = squad

In [7]:
X, y =  select_train_data_reg(squad, ['walkDistance', 'boosts', 'weaponsAcquired', 'damageDealt', 'heals'], percentage=0.5, to_select=15000)
rfs = random_forest_regressor_score(X, y)
svmrs = svm_regressor_score(X, y)
output_reg(rfs, svmrs)
Class winners: 15000, Class losers: 15000
Random Forest Regression Score = 0.732
Support Vector Machine Regression Score = 0.356

Para los otros matchType se omiten en este informe porque son similares y no aportan más información que lo que ya está.

Clustering

A continuación se aplicaran tecnicas de clustering para ver posibles cumulos de datos e intentar establecer mas relaciones entre ellos.

Para esto haremos clustering de 2 clases con cada uno de los 6 dataset, usaremos las 5 clases con mayor correlación con respecto a winPlacePerc, nuestra clase a predecir, y la misma ya mencionada.

A partir de este analisis se espera poder obtener más información con respecto a los datos y posiblemente poder refinar la predicción hasta lograr un valor cercano al 100%.

In [91]:
from sklearn.cluster import KMeans, DBSCAN
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA

import matplotlib.pyplot as plt
import itertools
from cycler import cycler

def get_normalized2(X):
  return (X - np.mean(X)) / np.std(X)

def get_normalized(X):
  return (X - np.min(X)) / (np.max(X) - np.min(X))

def get_iter_style():
  return itertools.cycle(cycler(marker=['s', '8', 'X', 'P', 'D', 'p', '*', 'H',
                                           9, 1, 2, 3, 4, '_', 'x', '|', 10, 11, 4]) * cycler(color=[
    '#e6194b', '#3cb44b', '#ffe119', '#0082c8', '#f58231', '#911eb4', '#46f0f0',
    '#f032e6', '#d2f53c', '#fabebe', '#008080', '#e6beff', '#aa6e28', '#fffac8',
    '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000080', '#808080'
]))

def kmeans_2d(X, k, columns, extra_title=""):
  kmeans_result = KMeans(n_clusters=k, random_state=0).fit(X)
  labels = kmeans_result.labels_
  centroids = kmeans_result.cluster_centers_
  
  iterstyle = get_iter_style()
  
  plt.figure(figsize=(20,10))

  #Xs = []
  for i in range(k):
    Xi = X[labels == i]
    Xi_x, Xi_y = Xi[:, 0], Xi[:, 1]
    #Xs.append((Xi_x, Xi_y))
    plt.scatter(Xi_x, Xi_y, **next(iterstyle))
    plt.scatter(centroids[i][0], centroids[i][1], c='black', s=300)
  
  #plt.scatter(X1_x, X1_y, c='red')
  #plt.scatter(X2_x, X2_y, c='blue')

  plt.xlabel(columns[0], fontsize=20)
  plt.ylabel(columns[1], fontsize=20)
  plt.suptitle('Kmeans clustering en 2D con k=%d%s' % (k, extra_title), fontsize=35)
  plt.tick_params(labelsize=20)

  plt.show()
  


def kmeans(X, k, extra_title=""):
  kmeans_result = KMeans(n_clusters=k, random_state=0).fit(X)
  labels = kmeans_result.labels_
  centroids = kmeans_result.cluster_centers_
  
  vis_X = PCA(n_components=2).fit_transform(X)
  
  iterstyle = get_iter_style()
  
  plt.figure(figsize=(20,10))

  #Xs = []
  for i in range(k):
    Xi = vis_X[labels == i]
    Xi_x, Xi_y = Xi[:, 0], Xi[:, 1]
    #Xs.append((Xi_x, Xi_y))
    plt.scatter(Xi_x, Xi_y, **next(iterstyle))
    plt.scatter(centroids[i][0], centroids[i][1], c='black', s=300)
  
  #plt.scatter(X1_x, X1_y, c='red')
  #plt.scatter(X2_x, X2_y, c='blue')

  plt.xlabel('X', fontsize=20)
  plt.ylabel('Y', fontsize=20)
  plt.suptitle('Kmeans clustering con k=%d%s' % (k, extra_title), fontsize=35)
  plt.tick_params(labelsize=20)

  plt.show()

Solos

Solo

Los parametros con mayor correlación para este dataset fueron walkDistance, WeaponsAcquired, boosts, damageDealt, kills.

Se haran experiemntos con KMeans entre cada uno de estos parametro y winPlacePerc, y veremos que es lo que sucede.

In [92]:
columns_to_select = ['walkDistance', 'winPlacePerc']
X, _ =  select_train_data_cls(solos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos con walkDistance y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [93]:
columns_to_select = ['weaponsAcquired', 'winPlacePerc']
X, _ =  select_train_data_cls(solos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])


kmeans_2d(X, 5, columns_to_select, ", Solos con weaponsAcquired y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [94]:
columns_to_select = ['boosts', 'winPlacePerc']
X, _ =  select_train_data_cls(solos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos con boosts y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [95]:
columns_to_select = ['damageDealt', 'winPlacePerc']
X, _ =  select_train_data_cls(solos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos con damageDealt y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [96]:
columns_to_select = ['kills', 'winPlacePerc']
X, _ =  select_train_data_cls(solos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos con kills y winPlacePerc")
Class winners: 15000, Class losers: 15000

Solo-fpp

Los parametros con mayor correlación para este dataset fueron walkDistance, WeaponsAcquired, boosts, damageDealt, kills. Al igual que en el anterior.

Se haran experiemntos con KMeans entre cada uno de estos parametro y winPlacePerc, y veremos que es lo que sucede.

In [97]:
columns_to_select = ['walkDistance', 'winPlacePerc']
X, _ =  select_train_data_cls(solosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos fpp con walkDistance y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [98]:
columns_to_select = ['weaponsAcquired', 'winPlacePerc']
X, _ =  select_train_data_cls(solosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])


kmeans_2d(X, 5, columns_to_select, ", Solos fpp con weaponsAcquired y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [99]:
columns_to_select = ['boosts', 'winPlacePerc']
X, _ =  select_train_data_cls(solosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos fpp con boosts y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [100]:
columns_to_select = ['damageDealt', 'winPlacePerc']
X, _ =  select_train_data_cls(solosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos fpp con damageDealt y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [101]:
columns_to_select = ['kills', 'winPlacePerc']
X, _ =  select_train_data_cls(solosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Solos fpp con kills y winPlacePerc")
Class winners: 15000, Class losers: 15000

Duos

Duo

Los parametros con mayor correlación para este dataset fueron walkDistance, boosts, WeaponsAcquired, damageDealt, kills.

Se haran experiemntos con KMeans entre cada uno de estos parametro y winPlacePerc, y veremos que es lo que sucede.

In [102]:
columns_to_select = ['walkDistance', 'winPlacePerc']
X, _ =  select_train_data_cls(duos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos con walkDistance y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [103]:
columns_to_select = ['boosts', 'winPlacePerc']
X, _ =  select_train_data_cls(duos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])


kmeans_2d(X, 5, columns_to_select, ", Duos con boosts y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [104]:
columns_to_select = ['weaponsAcquired', 'winPlacePerc']
X, _ =  select_train_data_cls(duos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos con weaponsAcquired y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [105]:
columns_to_select = ['damageDealt', 'winPlacePerc']
X, _ =  select_train_data_cls(duos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos con damageDealt y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [106]:
columns_to_select = ['kills', 'winPlacePerc']
X, _ =  select_train_data_cls(duos, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos con kills y winPlacePerc")
Class winners: 15000, Class losers: 15000

Duo-fpp

Los parametros con mayor correlación para este dataset fueron walkDistance, WeaponsAcquired, boosts, damageDealt, kills. Al igual que en el anterior.

Se haran experiemntos con KMeans entre cada uno de estos parametro y winPlacePerc, y veremos que es lo que sucede.

In [107]:
columns_to_select = ['walkDistance', 'winPlacePerc']
X, _ =  select_train_data_cls(duosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos fpp con walkDistance y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [108]:
columns_to_select = ['weaponsAcquired', 'winPlacePerc']
X, _ =  select_train_data_cls(duosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])


kmeans_2d(X, 5, columns_to_select, ", Duos fpp con weaponsAcquired y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [109]:
columns_to_select = ['boosts', 'winPlacePerc']
X, _ =  select_train_data_cls(duosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos fpp con boosts y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [110]:
columns_to_select = ['damageDealt', 'winPlacePerc']
X, _ =  select_train_data_cls(duosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos fpp con damageDealt y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [111]:
columns_to_select = ['kills', 'winPlacePerc']
X, _ =  select_train_data_cls(duosfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Duos fpp con kills y winPlacePerc")
Class winners: 15000, Class losers: 15000

Squads

Squad

Los parametros con mayor correlación para este dataset fueron walkDistance, boosts, weaponsAcquired, damageDealt, heals.

Se haran experiemntos con KMeans entre cada uno de estos parametro y winPlacePerc, y veremos que es lo que sucede.

In [112]:
columns_to_select = ['walkDistance', 'winPlacePerc']
X, _ =  select_train_data_cls(squad, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads con walkDistance y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [113]:
columns_to_select = ['boosts', 'winPlacePerc']
X, _ =  select_train_data_cls(squad, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])


kmeans_2d(X, 5, columns_to_select, ", Squads con boosts y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [114]:
columns_to_select = ['weaponsAcquired', 'winPlacePerc']
X, _ =  select_train_data_cls(squad, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads con weaponsAcquired y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [115]:
columns_to_select = ['damageDealt', 'winPlacePerc']
X, _ =  select_train_data_cls(squad, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads con damageDealt y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [116]:
columns_to_select = ['heals', 'winPlacePerc']
X, _ =  select_train_data_cls(squad, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads con heals y winPlacePerc")
Class winners: 15000, Class losers: 15000

Squad-fpp

Los parametros con mayor correlación para este dataset fueron walkDistance, boosts, weaponsAcquired, heals, damageDealt.

Se haran experiemntos con KMeans entre cada uno de estos parametro y winPlacePerc, y veremos que es lo que sucede.

In [117]:
columns_to_select = ['walkDistance', 'winPlacePerc']
X, _ =  select_train_data_cls(squadfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads fpp con walkDistance y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [118]:
columns_to_select = ['boosts', 'winPlacePerc']
X, _ =  select_train_data_cls(squadfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])


kmeans_2d(X, 5, columns_to_select, ", Squads fpp con boosts y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [119]:
columns_to_select = ['weaponsAcquired', 'winPlacePerc']
X, _ =  select_train_data_cls(squadfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads fpp con weaponsAcquired y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [120]:
columns_to_select = ['heals', 'winPlacePerc']
X, _ =  select_train_data_cls(squadfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads fpp con heals y winPlacePerc")
Class winners: 15000, Class losers: 15000
In [121]:
columns_to_select = ['damageDealt', 'winPlacePerc']
X, _ =  select_train_data_cls(squadfpp, columns_to_select, percentage=0.9, to_select=15000)
X[:, 0] = get_normalized(X[:, 0])

kmeans_2d(X, 5, columns_to_select, ", Squads fpp con damageDealt y winPlacePerc")
Class winners: 15000, Class losers: 15000